package com.example.mmlist2;


import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.example.mmlist2.mode.NavigationViewModel;
import com.example.mmlist2.storage.DatabaseHelper;
import com.example.mmlist2.storage.entity.Account;
import com.example.mmlist2.utils.FileImportExport;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;


import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;

import com.example.mmlist2.databinding.ActivityMainBinding;

import android.text.InputFilter;
import android.text.InputType;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import org.xutils.common.Callback;
import org.xutils.ex.HttpException;
import org.xutils.http.RequestParams;
import org.xutils.x;

import java.lang.reflect.Type;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import java.security.MessageDigest;

public class MainActivity extends AppCompatActivity {

    private AppBarConfiguration appBarConfiguration;
    private String accountsJson;
    private EditText captchaEdit;
    private EditText pcIpEdit;

    // 定义 ActivityResultLauncher
    private final ActivityResultLauncher<Intent> activityResultLauncher = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
                if (result.getResultCode() == Activity.RESULT_OK) {
                    Intent data = result.getData();
                    if (data != null) {
                        // 获取返回的数据，处理文件选择
                        Uri selectedFileUri = data.getData();
                        // 读取文件内容
                        FileImportExport.insert(this, selectedFileUri);
                    }
                }
            }
    );


    // 定义一个ActivityResultLauncher
    private final ActivityResultLauncher<Uri> openDocumentTreeLauncher = registerForActivityResult(
            new ActivityResultContracts.OpenDocumentTree(), result -> {
                // 处理返回的Uri
                if (result != null) {
                    // 用户成功选择了文档树
                    FileImportExport.saveFile(this, accountsJson, result);
                    FileImportExport.saveUriToSharedPreferences(this, result);
                } else {
                    // 用户取消了选择
                    Toast.makeText(this, "未选择保存的目录", Toast.LENGTH_SHORT).show();
                }

            }
    );


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // 绑定布局文件
        com.example.mmlist2.databinding.ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // 设置支持ActionBar
        setSupportActionBar(binding.toolbar);

        // 获取NavController对象
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);

        // 创建AppBarConfiguration对象，并将NavController的导航图传入
        appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();

        // 使用NavigationUI设置ActionBar与NavController的关联
        NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // 如果操作栏存在，这会将item添加到操作栏中。
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        //处理操作栏项的单击。只要您在AndroidManifest.xml中指定了父activity，操作栏就会自动处理Home/Up按钮上的单击。
        int id = item.getItemId();
        pcIpEdit = new EditText(this);

        if (id == R.id.export) {
            //导出数据库
            //弹窗提示
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("是否导出数据到本地？")
                    .setMessage("确认后，将导出所有数据到本地，数据将以JSON格式保存，请妥善保管。(如果第一次为0B，请尝试导出第二次)")
                    .setPositiveButton("确定", (dialog, which) -> export());

            AlertDialog dialog = builder.create(); // 创建AlertDialog
            dialog.show(); // 显示对话框
            return true;
        }

        if (id == R.id.importData) {
            //导入数据库
            //弹窗提示
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("是否导入数据？")
                    .setMessage("确认后，导入的数据将会覆盖当前数据库！")
                    .setPositiveButton("确定", (dialog, which) -> download());

            AlertDialog dialog = builder.create(); // 创建AlertDialog
            dialog.show(); // 显示对话框
            return true;
        }

        if (id == R.id.downFromPc) {
            String pcIp = getSavedPcIp();
            if ("-1".equals(pcIp)) {
                return true;
            }
            if (pcIp.isEmpty()) {
                Toast.makeText(this, "请先设置PC端IP", Toast.LENGTH_LONG).show();
                return true;
            }
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("是否导入数据？")
                    .setMessage("确认后，导入的数据会从PC端添加本地没有的数据！")
                    .setView(createCaptchaInput())
                    .setPositiveButton("确定", (dialog, which) -> downFromPc(pcIp));

            AlertDialog dialog = builder.create(); // 创建AlertDialog
            dialog.show(); // 显示对话框
            return true;
        }

        if (id == R.id.uploadToPc) {
            String pcIp = getSavedPcIp();
            if ("-1".equals(pcIp)) {
                return true;
            }
            if (pcIp.isEmpty()) {
                Toast.makeText(this, "请先设置PC端IP", Toast.LENGTH_LONG).show();
                return true;
            }
            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("是否上传数据？")
                    .setMessage("确认后，数据会从本地同步到PC端！")
                    .setView(createCaptchaInput())
                    .setPositiveButton("确定", (dialog, which) -> uploadToPc(pcIp));

            AlertDialog dialog = builder.create(); // 创建AlertDialog
            dialog.show(); // 显示对话框
            return true;
        }

        if (id == R.id.resetPcIp) {
            SharedPreferences prefs = this.getSharedPreferences("NetworkConfig", MODE_PRIVATE);
            String pcIp = prefs.getString("pc_ip", null);
            pcIpEdit.setText(pcIp);
            // 弹出输入对话框
            AlertDialog.Builder builder = getPcIpInputBuilder(prefs);
            builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
            AlertDialog dialog = builder.create();
            dialog.show();
        }

        //左上角返回箭头⬅
        NavigationViewModel navigationViewModel = new ViewModelProvider(this).get(NavigationViewModel.class);
        if (item.getItemId() == android.R.id.home) {
            // 设置标志位
            navigationViewModel.setReturningFromListFragment(true);
        }

        return super.onOptionsItemSelected(item);
    }

    private LinearLayout createCaptchaInput() {
        SharedPreferences prefs = this.getSharedPreferences("NetworkConfig", MODE_PRIVATE);
        String captcha = prefs.getString("captcha", "");

        captchaEdit = new EditText(this);
        captchaEdit.setInputType(InputType.TYPE_CLASS_NUMBER); // 只能输入数字
        captchaEdit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(6)}); // 限制输入长度为6位
        captchaEdit.setText(captcha);
        captchaEdit.setLayoutParams(new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1));

        TextView captchaLabel = new TextView(this);
        captchaLabel.setText("验证码");
        captchaLabel.setTextSize(18);
        captchaLabel.setPadding(40, 0, 10, 0);

        float density = getResources().getDisplayMetrics().density;
        Button clearButton = new Button(this);
        clearButton.setText("×");
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
                (int) (36 * density),
                (int) (36 * density)
        );
        layoutParams.rightMargin = (int) (10 * density);
        clearButton.setLayoutParams(layoutParams);
        clearButton.setBackgroundResource(R.drawable.circular_button_background);
        clearButton.setOnClickListener(v -> captchaEdit.setText(""));

        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.HORIZONTAL);
        layout.addView(captchaLabel);
        layout.addView(captchaEdit);
        layout.addView(clearButton);

        return layout;
    }

    private void saveCaptcha(String captcha) {
        // 保存输入的验证码到SharedPreferences
        this.getSharedPreferences("NetworkConfig", MODE_PRIVATE)
                .edit()
                .putString("captcha", captcha)
                .apply();
    }

    private String encryptString(String captcha, String data) {
        try {
            // 生成密钥（SHA-256哈希取前16字节）
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
            byte[] keyBytes = Arrays.copyOf(sha256.digest(captcha.getBytes(StandardCharsets.UTF_8)), 16);
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

            // 生成随机IV
            byte[] ivBytes = new byte[16];
            new SecureRandom().nextBytes(ivBytes);
            IvParameterSpec iv = new IvParameterSpec(ivBytes);

            // AES加密
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // 拼接IV和密文
            return bytesToHex(ivBytes) + bytesToHex(encrypted);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public String decryptString(String captcha, String encryptedData) {
        try {
            // 分离IV和密文
            byte[] ivBytes = hexToBytes(encryptedData.substring(0, 32));
            byte[] encryptedBytes = hexToBytes(encryptedData.substring(32));

            // 生成密钥
            MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
            byte[] keyBytes = Arrays.copyOf(sha256.digest(captcha.getBytes(StandardCharsets.UTF_8)), 16);
            SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");

            // AES解密
            IvParameterSpec iv = new IvParameterSpec(ivBytes);
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] decrypted = cipher.doFinal(encryptedBytes);

            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private byte[] hexToBytes(String hex) {
        byte[] result = new byte[hex.length() / 2];
        for (int i = 0; i < result.length; i++) {
            int index = i * 2;
            int val = Integer.parseInt(hex.substring(index, index + 2), 16);
            result[i] = (byte) val;
        }
        return result;
    }

    void downFromPc(String pcIp) {
        String captcha = captchaEdit.getText().toString();
        saveCaptcha(captcha);
        String url = "http://" + pcIp + "/api/getData";
        RequestParams params = new RequestParams(url);
        x.http().post(params, new Callback.CommonCallback<String>() {
            @Override
            public void onSuccess(String result) {
                //加载成功回调，返回获取到的数据
                if (!result.isEmpty()) {
                    // 将 JSON 字符串转换回 Map
                    Type type = new TypeReference<Map<String, Object>>() {
                    }.getType();
                    Map<String, Object> map = JSON.parseObject(result, type);
                    Object codeObj = map.get("code");
                    int code = codeObj != null ? (int) codeObj : -1;
                    Object accountsObj = map.get("data");
                    if (200 == code && accountsObj instanceof String) {
                        // 解密数据
                        String decryptedData = decryptString(captcha, (String) accountsObj);
                        // 类型转换
                        Type listTypeRef = new TypeReference<List<Map<String, Object>>>() {
                        }.getType();
                        List<Map<String, Object>> accounts = JSON.parseObject(decryptedData, listTypeRef);
                        try (DatabaseHelper helper = new DatabaseHelper(getApplicationContext())) {
                            int count = helper.addNewAccounts(accounts);
                            Toast.makeText(x.app(), "导入" + count + "条数据", Toast.LENGTH_SHORT).show();
                        } catch (Exception e) {
                            Toast.makeText(x.app(), "导入失败", Toast.LENGTH_SHORT).show();
                            throw new RuntimeException(e);
                        }
                    }

                }
            }

            @Override
            public void onError(Throwable ex, boolean isOnCallback) {
                if (ex instanceof HttpException) {
                    // 网络请求错误
                    HttpException httpException = (HttpException) ex;
                    int code = httpException.getCode();
                    String message = httpException.getMessage();
                    String result = httpException.getResult();
                    Log.e("upload", "code: " + code + ", message: " + message + ", result: " + result);
                    Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
                } else if (ex instanceof ConnectException) {
                    Toast.makeText(x.app(), "未找到PC端服务器", Toast.LENGTH_LONG).show();
                } else if (ex instanceof SocketTimeoutException) {
                    Toast.makeText(x.app(), "连接" + pcIp + "超时", Toast.LENGTH_LONG).show();
                } else {
                    showErrorMessage(ex.getMessage());
                }
                Log.e("upload", ex.toString());
            }

            @Override
            public void onCancelled(CancelledException cex) {
                Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
                Log.e("upload", "cancelled");
            }

            @Override
            public void onFinished() {
            }
        });
    }

    void uploadToPc(String pcIp) {
        String captcha = captchaEdit.getText().toString().trim();
        saveCaptcha(captcha);
        List<Account> accounts;
        try {
            DatabaseHelper db = new DatabaseHelper(this);
            accounts = db.getAllAccount();
            db.close();
            // 加密数据
            String encryptedData = encryptString(captcha, JSON.toJSONString(accounts));

            // 创建包含 code 和加密数据的 Map
            Map<String, Object> map = new HashMap<>();
            map.put("code", 200);
            map.put("data", encryptedData);

            // 调用服务器接口
            String url = "http://" + pcIp + "/api/setData";
            RequestParams params = new RequestParams(url);
            // 设置请求头，指定内容类型为 application/json
            params.setHeader("Content-Type", "application/json");
            // 将包含 code 和加密数据的 JSON 字符串作为请求体
            params.setBodyContent(JSON.toJSONString(map));
            x.http().post(params, new Callback.CommonCallback<String>() {
                @Override
                public void onSuccess(String result) {
                    Toast.makeText(x.app(), "上传成功", Toast.LENGTH_LONG).show();
                    //加载成功回调，返回获取到的数据
                    Log.i("upload", "result: " + result);
                }

                @Override
                public void onError(Throwable ex, boolean isOnCallback) {
                    if (ex instanceof HttpException) {
                        // 网络请求错误
                        HttpException httpException = (HttpException) ex;
                        int code = httpException.getCode();
                        String message = httpException.getMessage();
                        String result = httpException.getResult();
                        Log.e("upload", "code: " + code + ", message: " + message + ", result: " + result);
                        Toast.makeText(x.app(), result, Toast.LENGTH_LONG).show();
                    } else if (ex instanceof ConnectException) {
                        Toast.makeText(x.app(), "未找到PC端服务器", Toast.LENGTH_LONG).show();
                    } else if (ex instanceof SocketTimeoutException) {
                        Toast.makeText(x.app(), "连接" + pcIp + "超时", Toast.LENGTH_LONG).show();
                    } else {
                        showErrorMessage(ex.getMessage());
                    }

                    Log.e("upload", ex.toString());
                }

                @Override
                public void onCancelled(CancelledException cex) {
                    Toast.makeText(x.app(), "cancelled", Toast.LENGTH_LONG).show();
                    Log.e("upload", "cancelled");
                }

                @Override
                public void onFinished() {
//                    Toast.makeText(x.app(), "上传成功", Toast.LENGTH_LONG).show();
                }
            });
        } catch (Exception e) {
            Log.e("db", "error");
        }
    }

    void download() {
        //选择json文件
        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
        intent.setType("application/json");  // 设置文件类型为任意类型
        intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, false);  // 允许选择多个文件，false 表示不允许选择多个
        intent.addCategory(Intent.CATEGORY_OPENABLE);  // 让选择器能够打开文件
        activityResultLauncher.launch(intent);  // 启动活动
    }

    void export() {
        Map<String, Object> map = new HashMap<>();
        List<Account> accounts;
        try (DatabaseHelper db = new DatabaseHelper(this)) {
            accounts = db.getAccounts();
        }
        // 转换为JSON字符串
        map.put("accounts", accounts);
        // 保存密钥
        SharedPreferences sharedPreferences = this.getSharedPreferences("MyPreferences", MODE_PRIVATE);
        String encodedToken = sharedPreferences.getString("pass", null);
        map.put("key", encodedToken);
        accountsJson = JSON.toJSONString(map);
        // 从 SharedPreferences 读取保存的 Uri
        Uri savedUri = FileImportExport.getSavedUriFromSharedPreferences(this);
        if (savedUri != null) {
            // 如果 Uri 存在，直接使用该 Uri 进行文件保存操作
            FileImportExport.saveFile(this, accountsJson, savedUri);
        } else {
            // 如果 Uri 不存在，调用 openDocumentTreeLauncher.launch(null) 请求用户选择目录
            openDocumentTreeLauncher.launch(null);
        }
    }

    private String getSavedPcIp() {
        SharedPreferences prefs = this.getSharedPreferences("NetworkConfig", MODE_PRIVATE);
        String pcIp = prefs.getString("pc_ip", null);
        if (pcIp != null && !pcIp.isEmpty()) {
            return pcIp;
        }

        // 弹出输入对话框
        AlertDialog.Builder builder = getPcIpInputBuilder(prefs);
        builder.setNegativeButton("取消", (dialog, which) -> dialog.cancel());
        AlertDialog dialog = builder.create();
        dialog.show();
        return "-1";
    }

    private AlertDialog.Builder getPcIpInputBuilder(SharedPreferences prefs) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("获取PC端IP");
        builder.setMessage("请保持电脑和手机在同一个局域网下，输入PC端IP地址");
        pcIpEdit.setInputType(InputType.TYPE_CLASS_TEXT);
        builder.setView(pcIpEdit);
        builder.setPositiveButton("确定", (dialog, which) -> {
            String ip = pcIpEdit.getText().toString().trim();
            if (!ip.isEmpty()) {
                if (!ip.contains(":")) {
                    ip += ":65526";
                }
                // 保存输入的IP地址到SharedPreferences
                SharedPreferences.Editor editor = prefs.edit();
                editor.putString("pc_ip", ip);
                editor.apply();
                Toast.makeText(MainActivity.this, "IP地址保存成功，请重新同步", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(MainActivity.this, "IP地址不能为空", Toast.LENGTH_SHORT).show();
            }
        });
        return builder;
    }

    private void showErrorMessage(String message) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setTitle("错误信息");
        builder.setMessage(message);
        builder.setPositiveButton("复制", (dialog, which) -> {
            // 复制错误信息到剪贴板
            android.content.ClipboardManager clipboard = (android.content.ClipboardManager) getSystemService(android.content.Context.CLIPBOARD_SERVICE);
            android.content.ClipData clip = android.content.ClipData.newPlainText("Error Message", message);
            clipboard.setPrimaryClip(clip);
            Toast.makeText(this, "错误信息已复制", Toast.LENGTH_SHORT).show();
        });
        builder.setNegativeButton("关闭", (dialog, which) -> dialog.dismiss());
        AlertDialog dialog = builder.create();
        dialog.show();
    }


    @Override
    public boolean onSupportNavigateUp() {
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
        return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp();
    }
}